﻿namespace MicroCloud.Http
{
    /// <summary>
    /// Http客户端通信加密解密器
    /// </summary>
    public class ClientHttpCrypto : IClientHttpCrypto
    {
        //字段
        private readonly ILogger _logger;
        private readonly TransmissionEncryptor _encryptor;
        private readonly string _clientPublicKey;

        #region "构造函数"
        #region "初始化一个Http客户端通信加密解密器的新实例"
        /// <summary>
        /// 初始化一个Http客户端通信加密解密器 <see cref="ClientHttpCrypto"/> 的新实例
        /// </summary>
        /// <param name="provider"></param>
        public ClientHttpCrypto(IServiceProvider provider)
        {
            _logger = provider.GetLogger(typeof(ClientHttpCrypto));
            MicroCloudOptions options = provider.GetMicroCloudOptions();
            if (options.HttpEncrypt?.Enabled == true)
            {
                HttpEncryptOption httpEncrypt = options.HttpEncrypt;
                string hostPublicKey = httpEncrypt.HostPublicKey;
                if (string.IsNullOrEmpty(hostPublicKey))
                {
                    throw new Exception(I18N.T("配置文件中 HttpEncrypt 节点的 HostPublicKey 不能为空"));
                }
                RsaAlgorithm rsa = new();
                _encryptor = new TransmissionEncryptor(rsa.PrivateKey, hostPublicKey);
                _clientPublicKey = rsa.PublicKey;
                _logger.LogDebug("使用新的客户端RSA私钥和服务端公钥创建客户端通信加密器");
            }
        }
        #endregion

        #endregion

        #region "方法"
        #region "将要发往服务器的请求进行加密"
        /// <summary>
        /// 将要发往服务器的请求进行加密 
        /// </summary>
        /// <param name="request">未加密的请求</param>
        /// <returns>加密后的请求</returns>
        public virtual async Task<HttpRequestMessage> EncryptRequest(HttpRequestMessage request)
        {
            if (_encryptor == null || string.IsNullOrEmpty(_clientPublicKey) || request.Method == HttpMethod.Get || request.Content == null)
            {
                return request;
            }

            string data = await request.Content.ReadAsStringAsync();
            data = _encryptor.EncryptData(data);
            request = request.CreateNew(data);
            request.Headers.Add(HttpHeaderNames.ClientPublicKey, _clientPublicKey);
            _logger.LogDebug("使用客户端公钥加密客户端请求数据");
            return request;
        }
        #endregion
        #region "解密从服务器收到的响应"
        /// <summary>
        /// 解密从服务器收到的响应
        /// </summary>
        /// <param name="response">加密的响应</param>
        /// <returns>解密后的响应</returns>
        public virtual async Task<HttpResponseMessage> DecryptResponse(HttpResponseMessage response)
        {
            if (_encryptor == null || !response.IsSuccessStatusCode)
            {
                return response;
            }

            string data = await response.Content.ReadAsStringAsync();
            if (string.IsNullOrEmpty(data))
            {
                return response;
            }

            try
            {
                data = _encryptor.DecryptAndVerifyData(data);
                if (data == null)
                {
                    throw new Exception(I18N.T(Resources.Http_Security_Client_VerifyResponse_Failt));
                }
                response = response.CreateNew(data);
                _logger.LogDebug("使用客户端私钥解密响应数据，并使用服务端公钥验证数据。");
                return response;
            }
            catch (System.Exception ex)
            {
                _logger.LogError(Resources.Http_Seciruty_Client_DecryptResponse_Failt, ex);
                response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
                return response;
            }
        }
        #endregion

        #endregion

    }

}
